package com.rul.mars.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.aliyuncs.exceptions.ClientException;
import com.rul.mars.common.api.CommonResult;
import com.rul.mars.common.api.CommonResultCode;
import com.rul.mars.common.constant.AuthConstant;
import com.rul.mars.common.constant.UserStatusConstant;
import com.rul.mars.common.domain.UserDto;
import com.rul.mars.common.exception.Asserts;
import com.rul.mars.common.service.SendSmsService;
import com.rul.mars.mbg.dao.UserRoleRelationDao;
import com.rul.mars.mbg.mapper.UserMapper;
import com.rul.mars.mbg.mapper.UserRoleRelationMapper;
import com.rul.mars.mbg.model.*;
import com.rul.mars.user.service.AuthService;
import com.rul.mars.user.service.RoleService;
import com.rul.mars.user.service.UserCacheService;
import com.rul.mars.user.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 *
 * @author RuL
 */
@Service
public class UserServiceImpl implements UserService {
    private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRoleRelationDao userRoleRelationDao;
    @Autowired
    private UserRoleRelationMapper userRoleRelationMapper;
    @Autowired
    private RoleService roleService;

    @Autowired
    private AuthService authService;

    @Autowired
    private Random random;
    @Autowired
    private SendSmsService sendSmsService;
    @Autowired
    private UserCacheService userCacheService;
    @Autowired
    private HttpServletRequest request;
    @Value("${role.customer.name}")
    private String CUSTOMER_ROLE_NAME;


    /**
     * 用户注册
     *
     * @param username 用户名
     * @param password 密码
     * @param phone    手机号
     * @param authCode 手机验证码
     */
    @Override
    public void register(String username, String password, String phone, String authCode) {
        if (!verifyAuthCode(phone, authCode)) {
            Asserts.fail("验证码错误");
        }
        if (existUser(username, phone)) {
            Asserts.fail("用户已存在");
        }

        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setPhone(phone);
        user.setStatus(UserStatusConstant.ENABLE);

        int count = userMapper.insertSelective(user);
        if (count > 0) {
            Role customerRole = roleService.getRoleByName(CUSTOMER_ROLE_NAME);
            updateRole(user.getId(), Collections.singletonList(customerRole.getId()));
        }
    }

    /**
     * 用户登录
     *
     * @param username 用户名
     * @param password 密码
     * @return 登录结果
     */
    @Override
    public CommonResult login(String username, String password) {
        if (CharSequenceUtil.isBlank(username) || CharSequenceUtil.isBlank(password)) {
            Asserts.fail("用户名和密码不能为空");
        }
        //获取Token所需参数
        Map<String, String> params = new HashMap<>();
        params.put("client_id", AuthConstant.WEB_CLIENT_ID);
        params.put("client_secret", AuthConstant.WEB_CLIENT_SECRET);
        params.put("grant_type", "password");
        params.put("username", username);
        params.put("password", password);
        //获取Token信息
        return authService.getAccessToken(params);
    }

    /**
     * 修改密码
     *
     * @param password 新密码
     * @param phone    手机号
     * @param authCode 手机验证码
     */
    @Override
    public void updatePassword(String password, String phone, String authCode) {
        User user = currentUser();
        if (!phone.equals(user.getPhone())) {
            Asserts.fail("手机号错误");
        }
        if (!verifyAuthCode(phone, authCode)) {
            Asserts.fail("验证码错误");
        }

        //更新密码
        user.setPassword(SecureUtil.md5(password));
        userMapper.updateByPrimaryKeySelective(user);
        //用户缓存失效
        userCacheService.deleteUser(user.getId());
    }

    /**
     * 更新用户信息
     *
     * @param user 需更新的用户信息
     */
    @Override
    public void updateInfo(User user) {
        userMapper.updateByPrimaryKeySelective(user);
        //缓存失效
        userCacheService.deleteUser(user.getId());
    }

    /**
     * 生成并发送手机验证码
     *
     * @param phone 手机号
     */
    @Override
    public void generateAuthCode(String phone) {
        StringBuilder sbr = new StringBuilder();
        for (int i = 0; i < 6; i++) {
            sbr.append(random.nextInt(10));
        }
        String authCode = sbr.toString();
        try {
            boolean sendSuccess = sendSmsService.sendAuthCode(phone, authCode);
            if (sendSuccess) {
                //将验证码存入缓存
                userCacheService.setAuthCode(phone, sbr.toString());
            }
        } catch (ClientException e) {
            Asserts.fail("验证码发送失败");
            e.printStackTrace();
        }
    }

    /**
     * 当前会话用户
     *
     * @return 当前会话用户信息
     */
    @Override
    public User currentUser() {
        //从Token中获取用户信息JSON字符串
        String userStr = request.getHeader(AuthConstant.USER_TOKEN_HEADER);
        if (StrUtil.isEmpty(userStr)) {
            Asserts.fail(CommonResultCode.UNAUTHORIZED);
        }
        //将JSON字符串转为UserDto对象
        UserDto userDto = JSONUtil.toBean(userStr, UserDto.class);

        User member = userCacheService.getUser(userDto.getId());
        if (member == null) {
            member = getById(userDto.getId());
            userCacheService.setUser(member);
        }
        return member;
    }

    /**
     * 禁用用户账号
     *
     * @param id 用户ID
     * @return 操作结果
     */
    @Override
    public boolean disableUser(Long id) {
        User user = userMapper.selectByPrimaryKey(id);
        user.setStatus(UserStatusConstant.DISABLE);
        int rows = userMapper.updateByPrimaryKeySelective(user);
        return rows == 1;
    }

    /**
     * 删除用户
     *
     * @param id 用户ID
     * @return 删除结果
     */
    @Override
    public boolean deleteUser(Long id) {
        int rows = userMapper.deleteByPrimaryKey(id);
        return rows == 1;
    }

    /**
     * 通过用户名查询用户信息Dto
     *
     * @param username 用户名
     * @return 用户信息Dto
     */
    @Override
    public UserDto loadUserByUsername(String username) {
        //用户信息
        User user = getByUsername(username);

        if(user!=null) {
            //转为UserDto
            UserDto userDto = BeanUtil.copyProperties(user, UserDto.class);
            //用户角色
            List<Role> roles = userRoleRelationDao.getRoleListByUserId(user.getId());

            if (CollUtil.isNotEmpty(roles)) {
                List<String> roleStrList = roles.stream()
                        .map(Role::getName)
                        .collect(Collectors.toList());
                userDto.setRoles(roleStrList);
            }
            return userDto;
        }
        return null;

    }

    /**
     * 获取用户的角色信息
     *
     * @param userId 用户ID
     * @return 用户角色信息
     */
    @Override
    public List<Role> getRoleList(Long userId) {
        return userRoleRelationDao.getRoleListByUserId(userId);
    }

    /**
     * 更新用户角色关系
     *
     * @param userId  用户ID
     * @param roleIds 角色ID列表
     * @return 更新结果
     */
    @Override
    public int updateRole(Long userId, List<Long> roleIds) {
        int count = roleIds == null ? 0 : roleIds.size();
        UserRoleRelationExample example = new UserRoleRelationExample();
        example.createCriteria()
                .andUserIdEqualTo(userId);
        //删除原有关系
        userRoleRelationMapper.deleteByExample(example);

        if (CollUtil.isNotEmpty(roleIds)) {
            //建立新关系
            List<UserRoleRelation> userRoleRelationList = new ArrayList<>();
            for (Long roleId : roleIds) {
                UserRoleRelation userRoleRelation = new UserRoleRelation();
                userRoleRelation.setRoleId(roleId);
                userRoleRelation.setUserId(userId);
                userRoleRelationList.add(userRoleRelation);
            }
            userRoleRelationDao.insertList(userRoleRelationList);
        }
        return count;
    }


    /**
     * 根据用户ID查询用户信息
     *
     * @param id 用户ID
     * @return 用户信息
     */
    public User getById(Long id) {
        User user = userCacheService.getUser(id);
        if (user == null) {
            user = userMapper.selectByPrimaryKey(id);
            //将该用户信息加入缓存
            userCacheService.setUser(user);
        }
        return user;
    }

    /**
     * 根据用户名查询用户信息
     *
     * @param username 用户名
     * @return 用户信息
     */
    public User getByUsername(String username) {
        UserExample example = new UserExample();
        example.createCriteria()
                .andUsernameEqualTo(username);
        List<User> userList = userMapper.selectByExample(example);

        if (CollUtil.isNotEmpty(userList)) {
            return userList.get(0);
        }
        return null;
    }

    /**
     * 根据用户名和手机号查询用户是否存在
     *
     * @param username 用户名
     * @param phone    手机号
     * @return 用户是否存在
     */
    public boolean existUser(String username, String phone) {
        UserExample example = new UserExample();
        example.createCriteria().andUsernameEqualTo(username);
        example.or(example.createCriteria().andPhoneEqualTo(phone));
        List<User> userList = userMapper.selectByExample(example);

        return !CollUtil.isEmpty(userList);
    }

    /**
     * 验证手机验证码是否正确
     *
     * @param phone    手机号
     * @param authCode 验证码
     * @return 验证码是否正确
     */
    public boolean verifyAuthCode(String phone, String authCode) {
        String correctAuthCode = userCacheService.getAuthCode(phone);
        if (CharSequenceUtil.hasBlank(authCode)) {
            return false;
        }
        return authCode.equals(correctAuthCode);
    }

}
